#ifndef __M_LOGGER_HPP__
#define __M_LOGGER_HPP__

/*
    完成日志器模块：
        1、抽象日志器基类
        2、派生出不同的子类，（同步&异步日志器类）
*/

#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
#include <mutex>
#include <memory>
#include <stdarg.h>
#include <sstream>
#include <cassert>
#include <unordered_map>
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include "buffer.hpp"

namespace mylog
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name,LogLevel::value level,Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name), _limit_level(level), _formatter(formatter), _sinks(sinks.begin(), sinks.end())
        {}

        //获取日志器名称
        const std::string& name()
        {
            return _logger_name;
        } 

        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            //1、判断当前的日志是否达到输出等级
            if(_limit_level > LogLevel::value::DEBUG)
                return;
            //2、对格式化fmt字符串和不定参数进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char *res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);
            //3、将日志消息字符串进行序列化，得到LogMsg对象
            serialize(LogLevel::value::DEBUG, file, line, res);
            
            free(res);
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            //1、判断当前的日志是否达到输出等级
            if(_limit_level > LogLevel::value::INFO)
                return;
            //2、对格式化fmt字符串和不定参数进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char *res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);
            serialize(LogLevel::value::INFO, file, line, res);
            
            free(res);
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            //1、判断当前的日志是否达到输出等级
            if(_limit_level > LogLevel::value::WARN)
                return;
            //2、对格式化fmt字符串和不定参数进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char *res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);
            //3、将日志消息字符串进行序列化，得到LogMsg对象
            serialize(LogLevel::value::WARN, file, line, res);
            
            free(res);
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            //1、判断当前的日志是否达到输出等级
            if(_limit_level > LogLevel::value::ERROR)
                return;
            //2、对格式化fmt字符串和不定参数进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char *res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);
            //3、将日志消息字符串进行序列化，得到LogMsg对象
            serialize(LogLevel::value::ERROR, file, line, res);
            
            free(res);
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            //1、判断当前的日志是否达到输出等级
            if(_limit_level > LogLevel::value::FATAL)
                return;
            //2、对格式化fmt字符串和不定参数进行字符串组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char *res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);
            //3、将日志消息字符串进行序列化，得到LogMsg对象
            serialize(LogLevel::value::FATAL, file, line, res);
            
            free(res);
        }
    private:
        void serialize(LogLevel::value level, const std::string &file, size_t line, char *str)
        {
            //3、构造LogMsg对象
            LogMsg msg(level, line, file, _logger_name, str);
            //4、通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::stringstream ss;
            _formatter->format(ss,msg);
            //5、进行日志落地
            log(ss.str().c_str(),ss.str().size());
        }
        virtual void log(const char* data, size_t len) = 0;
    protected:
        std::mutex _mutex; //互斥锁，保护_sinks
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level; //atomic原子操作，保证线程安全
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class SyncLogger: public Logger
    {
    public:
        SyncLogger(const std::string &logger_name,LogLevel::value level,Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            :Logger(logger_name,level,formatter,sinks) 
        {}
    protected:
        void log(const char* data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_sinks.empty())
                return;
            for(auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger: public Logger
    {
    public:
        AsyncLogger(const std::string& logger_name,
                    LogLevel::value level,
                    Formatter::ptr& formatter,
                    std::vector<LogSink::ptr>& sinks,
                    AsyncType looper_type)
            :Logger(logger_name,level,formatter,sinks),
             _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1),looper_type))
        {}
        void realLog(Buffer &buf)
        {
            //这里不需要加锁，异步线程只是串行处理日志落地
            if(_sinks.empty())
                return;
            for(auto &sink : _sinks)
            {
                sink->log(buf.begin(), buf.readAbleSize());
            }
        }
        void log(const char* data, size_t len) override
        {
            _looper->push(data, len);
        }
    private:
        AsyncLooper::ptr _looper;
    };

    /*
        使用建造者模型，使用简化版本，不需要指挥者（因为没有顺序要求）
        1、抽象一个日志器建造者类(完成日志器对象所需要零部件的构建 & 日志器的构建)
            1、设置日志器类型
            2、将不同类型日志器的创建放到同一个日志器建造者中完成
        2、派生具体的日志器建造者类 -- 局部日志器建造者 & 全局的日志器建造者
            （后面添加了全局单例管理器之后，将日志器添加全局管理）
    */
   enum class LoggerType
   {
        LOGGER_SYNC,
        LOGGER_ASYNC
   };
   class LoggerBuilder
   {
    public:
        LoggerBuilder()
            : _logger_type(LoggerType::LOGGER_SYNC),
              _limit_level(LogLevel::value::DEBUG),
              _looper_type(AsyncType::ASYNC_SAFE)
        {}
        void buildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }
        void buildEnableUnSafeAsync()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
        }
        void buildLoggerName(const std::string &name)
        {
            _logger_name = name;
        }
        void buildLoggerLevel(LogLevel::value level)
        {
            _limit_level = level;
        }
        void buildLoggerFormatter(const std::string &pattern = "")
        {
            if(pattern == "")
            {
                _formatter = std::make_shared<Formatter>();
                return;
            }
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template<typename SinkType, typename... Args>
        void buildLoggerSink(Args&&... args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr build() = 0;
    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        LogLevel::value _limit_level;
        std::vector<LogSink::ptr> _sinks;
        Formatter::ptr _formatter;
   };
    // 2、派生具体的日志器建造者类 -- 局部日志器建造者 & 全局的日志器建造者
    //  （后面添加了全局单例管理器之后，将日志器添加全局管理）
    class LocalLoggerBuilder: public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                buildLoggerSink<StdoutSink>();
            }
            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };

    //设计一个全局日志器的单例日志器对象管理器
    class LoggerManager
    {
    public:
        static LoggerManager& getInstance()
        {
            //c++11之后，针对静态局部变量，编译器在编译层面实现了线程安全
            //当静态局部变量在没有构造完成之前，其他的线程进入就会阻塞
            static LoggerManager eton;
            return eton;
        }
        void addLogger(Logger::ptr &logger)
        {
            if(hasLogger(logger->name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }
        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            return it != _loggers.end();
        }
        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
                return nullptr;
            return it->second;
        }
        Logger::ptr rootLogger()
        {
            return _root_logger;
        }
    private:
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuilder());
            builder->buildLoggerType(LoggerType::LOGGER_SYNC);
            builder->buildLoggerName("root_logger");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair(_root_logger->name(), _root_logger));
        }
        ~LoggerManager()
        {}

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;
        std::unordered_map<std::string, Logger::ptr>_loggers; 
    };

    //设计一个全局日志器的建造者--在局部的基础上增加一个功能：将日志器添加到单例对象中
    class GlobalLoggerBuilder: public LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<GlobalLoggerBuilder>;
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                buildLoggerSink<StdoutSink>();
            }
            Logger::ptr logger;
            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            //添加到全局日志器对象管理器
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}

#endif